﻿using System;
using System.Data;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Windows.Forms;
using System.IO;
using System.Security.Principal;
using System.DirectoryServices;

/** @file dbServices.cs Файл содержит служебный инициализирующий код
 * @author Maxim Terentyev
 */

namespace AccidentCards
{
    class dbServices
    {
        private static bool connected = false;
        public static int operatorRole = 0;
        public enum OperatorRoles { ReaderRole = 1, AuthorRole };
        private static SqlConnection sqlConn;
        public static string globalConnectionString = "Data Source=(local);DataBase=DTP;Integrated Security=SSPI";
        public static string globalDatabaseName = "DTP";
        static public String globalSID = String.Empty;
        private static string globalUserDomainString = String.Empty;
        public static string globalUserWindows = String.Empty;
        public static bool Connected
        {
            get
            {
                return connected;
            }
        }
        public static SqlConnection SqlConn
        {
            get
            {
                return sqlConn;
            }
        }
        public static bool Connect()
        {
            try
            {
                sqlConn = new SqlConnection(globalConnectionString);
                sqlConn.Open();
                if (sqlConn.State == ConnectionState.Open)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString(), "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return false;
        }
        /** @fn bool GetOperatorRole() 
        * @brief Получить роль оператора
        * @details Получить роль пользователя в соответствии с ролью из СУБД
        * @return Возвращает true в случае успеха, false в противном случае
        */
        public static bool GetOperatorRole()
        {
            operatorRole = 0;
            if (CheckRole("dtp_reader"))
            {
                operatorRole = Convert.ToInt32(OperatorRoles.ReaderRole);
                return true;
            }
            else if (CheckRole("dtp_author"))
            {
                operatorRole = Convert.ToInt32( OperatorRoles.AuthorRole);
                return true;
            }
            else
            {
                return false;
            }
        }
        /** @fn bool CheckRole(string role)
         * @brief Проверка принадлежности пользователя к определенном роли
         * @param[in] role - Роль для проверки
         * @return Возвращает true если пользователь принадлежит к указанной роли, false в противном случае
         */
        private static bool CheckRole(string role)
        {
            bool result = false;
            if (!dbServices.Connect())
            {
                return false;
            }
            DataTable dt = new DataTable();
            string sQuery = "SELECT IS_MEMBER('" + role + "')";
            try
            {
                SqlDataAdapter dataAdapter = new SqlDataAdapter(sQuery, sqlConn);
                dataAdapter = new SqlDataAdapter(sQuery, sqlConn);
                dataAdapter.Fill(dt);
                string access_value = dt.Rows[0][0].ToString();
                result = (access_value == "1");
                dataAdapter.Dispose();
            }
            catch (SqlException sEx)
            {
                MessageBox.Show(sEx.Message.ToString(), "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                result = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString(), "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                result = false;
            }
            finally
            {
                dbServices.Close();
            }

            return result;
        }

        public static void Close()
        {
            if (SqlConn.State == ConnectionState.Open)
            {
                SqlConn.Close();
            }

        }

        /** @fn bool TestDbAccess()
         * @brief Проверка наличия доступа к БД
         * @return Возвращает true если имеется доступ к БД, false в противном случае
         */
        static public bool TestDbAccess()
        {
            bool rslt = true;
            using (SqlConnection sql_con = new SqlConnection(globalConnectionString))
                try
                {
                    SqlCommand cmd = new SqlCommand("SELECT HAS_DBACCESS('" + globalDatabaseName + "')", sql_con);
                    cmd.Connection.Open();
                    rslt = cmd.ExecuteScalar().ToString() == "1";
                }
                catch (SqlException sEx)
                {
                    MessageBox.Show(sEx.Message.ToString(), "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    rslt = false;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message.ToString(), "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    rslt = false;
                }
                finally
                {
                    sql_con.Close();
                }

            return rslt;
        }

        /** @fn void InitDb(string cfgFileName)
         * @brief Инициализация приложения, чтение конфигурации и идентификация пользователя
         * @param[in] cfgFileName - путь к конфигурационному файлу
         */
        public static void InitDb(string cfgFileName)
        {
            FileInfo fi = new FileInfo(cfgFileName);
            if (fi.Exists)
            {
                try
                {
                    string[] s = File.ReadAllLines(cfgFileName);
                    if (s[0].Trim().Length != 0) globalConnectionString = s[0];
                    globalUserDomainString = s[1];
                }
                catch
                {
                    MessageBox.Show("Неверный формат файла конфигурации. Приложение будет закрыто.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    Environment.Exit(0);
                }
            }
            else
            {
                MessageBox.Show("Отсутствует файл конфигурации. Приложение будет закрыто.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                Environment.Exit(0);
            }

            String sAdUserName = String.Empty;
            GetFullNameCurrentUserFromAd(ref sAdUserName, ref globalSID);
            globalUserWindows = string.Format("{0}{1}{2}]", WindowsIdentity.GetCurrent().Name, (sAdUserName.Length > 0 ? " (" + sAdUserName + ") [" : " ["), System.Environment.MachineName);
            if (!WindowsIdentity.GetCurrent().IsAuthenticated)
            {
                MessageBox.Show("Вы не авторизованы Windows", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                Environment.Exit(0);
            }

            if (!TestDbAccess())
            {
                MessageBox.Show("Нет доступа к базе данных", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                Environment.Exit(0);
            }
            if (!GetOperatorRole())
            {
                MessageBox.Show("Невозможно определить роль пользователя", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                Environment.Exit(0);
            }
        }

        /** @fn void GetFullNameCurrentUserFromAd(ref String fullName, ref String sid)
     * @brief Получить полное имя пользователя из ActiveDirectory
     * @param[out] fullName - Имя пользователя
     * @param[out] sid - SID пользователя
     */
        static public void GetFullNameCurrentUserFromAd(ref String fullName, ref String sid)
        {
            String rslt = String.Empty;
            try
            {
                DirectoryEntry entry = new DirectoryEntry(globalUserDomainString);

                using (DirectorySearcher adSearcher = new DirectorySearcher(entry))
                {
                    adSearcher.Filter = "sAMAccountName=" + System.Environment.UserName;
                    adSearcher.PropertiesToLoad.Add("displayName");
                    adSearcher.PropertiesToLoad.Add("SAMAccountName");
                    adSearcher.PropertiesToLoad.Add("givenName");
                    adSearcher.PropertiesToLoad.Add("sn");
                    adSearcher.PropertiesToLoad.Add("mail");
                    adSearcher.PropertiesToLoad.Add("objectSid");

                    using (SearchResultCollection adResults = adSearcher.FindAll())
                    {
                        foreach (SearchResult adResult in adResults)
                        {
                            if (adResult.Properties["objectSid"].Count > 0)
                                sid = new SecurityIdentifier((Byte[])adResult.Properties["objectSid"][0], 0).ToString();
                            if (adResult.Properties["givenName"].Count > 0)
                                rslt += adResult.Properties["givenName"][0];
                            if (adResult.Properties["sn"].Count > 0)
                            {
                                if (rslt.Length != 0) rslt += " ";
                                rslt += adResult.Properties["sn"][0];
                            }
                        }
                    }
                }

                if (String.IsNullOrEmpty(sid))
                {
                    Exception ex = new Exception("Current user not in AD.");
                    throw ex;
                }

            }
            catch (Exception ex)
            {
                //domain not exists or computer not connected to domain
                MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                Environment.Exit(0);
            }
            fullName = rslt;
        }
    }
}
